/*
 * $Id: QELogDocument.m 248 2008-09-08 15:31:38Z jon $
 * Sleeper
 *
 * Created by Jon Gordon on 7/27/08
 * Copyright Jon Gordon.  All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#import "QELogDocument.h"

#import "QEEntryData.h"
#import "QELogModel.h"


static NSString *MAIN_WINDOW_NIB_NAME = @"LogWindow";
static NSString *SECTIONS_WINDOW_NIB_NAME = @"SectionsWindow";


@interface QELogDocument (private)
#pragma mark PRIMITIVE OPERATIONS
- (void)restoreExchange:(NSString *)value;
- (void)uncreateQso:(QEContact *)qso fromExchange:(NSString *)src;

#pragma mark PRIVATE FIELDS
- (QELogWindowController *)logWindow;
- (void)setLogWindow:(QELogWindowController *)newValue;

- (QESectionsWindowController *)secWindow;
- (void)setSecWindow:(QESectionsWindowController *)newValue;
@end


@implementation QELogDocument
#pragma mark CREATION/DESTRUCTION
- (id)init
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    self = [super init];
    if (self) {
        logWindow = nil;
        secWindow = nil;
        
        [self setModel:[[[QELogModel alloc] init] autorelease]];
    } // if
    return self;
} // init


- (void)dealloc
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [self setModel:nil];
    [self setLogWindow:nil];
    [self setSecWindow:nil];
    [super dealloc];
} // dealloc


#pragma mark OPERATIONS
- (void)updateSentExchange
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    
    static const NSString *CALL_PLACEHOLDER = @"<call>";
    static const NSString *CAT_PLACEHOLDER = @"<P>";
    static const NSString *CHECK_PLACEHOLDER = @"<check>";
    static const NSString *SECTION_PLACEHOLDER = @"<section>";
    
    QEEntryData *ed = [[self model] entryData];
    NSMutableString *buffer = [[NSMutableString alloc] init];
    
    if ((nil != [ed entryCallsign]) && (0 < [[ed entryCallsign] length])) {
        [buffer appendFormat:@"%@ ", [ed entryCallsign]];
    } else {
        [buffer appendFormat:@"%@ ", CALL_PLACEHOLDER];
    } // else
    
    [buffer appendFormat:@"%d ", [[self model] nextSerial]];
    
    if ((nil != [ed category]) && (0 < [[ed category] length])) {
        [buffer appendFormat:@"%@ ", [ed category]];
    } else { 
        [buffer appendFormat:@"%@ ", CAT_PLACEHOLDER];
    } // else
    
    if (nil != [ed check]) {
        [buffer appendFormat:@"%02d ", [[ed check] intValue]];
    } else {
        [buffer appendFormat:@"%@ ", CHECK_PLACEHOLDER];
    } // else
    
    if ((nil != [ed section]) && (0 < [[ed section] length])) {
        [buffer appendFormat:@"%@", [ed section]];
    } else {
        [buffer appendFormat:@"%@", SECTION_PLACEHOLDER];
    } // else
    
    [[self logWindow] setOutExchange:[NSString stringWithString:buffer]];
    [buffer release];
} // updateSentExchange


- (void)exportCabrillo
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSSavePanel *savePanel = [NSSavePanel savePanel];
    SEL sel = @selector(exportPanelDidEnd:returnCode:contextInfo:);
    [savePanel beginSheetForDirectory:@"~/Documents"
                                 file:@"cabrillo.txt"
                       modalForWindow:[self windowForSheet]
                        modalDelegate:self
                       didEndSelector:sel
                          contextInfo:nil];
} // exportCabrillo


- (void)exportPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (NSOKButton == returnCode) {
        NSString *filename = [[sheet filename] stringByExpandingTildeInPath];
        [self saveAsCabrillo:filename];
    } else {
        NSLog(@"  user cancelled Cabrillo log export");
    } // else
} // exportPanelDidEnd:returnCode:contextInfo:


- (void)saveAsCabrillo:(NSString *)filename
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSLog(@"  exporting Cabrillo log to file \"%@\"", filename);
    NSString *source = [[self model] dataAsCabrilloText];
    [source writeToFile:filename atomically:YES encoding:NSASCIIStringEncoding error:NULL];
} // saveAsCabrillo:


- (void)clearExchange
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSString *exchange = [[self logWindow] entrySrc];
    [[[self undoManager] prepareWithInvocationTarget:self] restoreExchange:exchange];
    [[self logWindow] setEntrySrc:@""];
    [[self undoManager] setActionName:@"Clear"];
} // clearExchange


- (void)createQsoWithNewExchange:(NSString *)newExchange
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSString *exchange = [[self logWindow] entrySrc];
    QEContact *newContact = [[self model] addContact];
    [[[self undoManager] prepareWithInvocationTarget:self] uncreateQso:newContact fromExchange:exchange];
    [[self undoManager] setActionName:@"Enter"];
    [[self logWindow] setEntrySrc:newExchange];
    [self updateSentExchange];
} // createQsoWithNewExchange:


- (void)showSections {
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (nil == [self secWindow]) {
        NSLog(@"  loading nib");
        [NSBundle loadNibNamed:SECTIONS_WINDOW_NIB_NAME owner:self];
        [self setSecWindow:[[QESectionsWindowController alloc]
                            initWithWindowNibName:SECTIONS_WINDOW_NIB_NAME
                            owner:self]];
    } // if
    NSLog(@"  showing window");
    [[self secWindow] showWindow:self];
    NSLog(@"  returning");
} // showSections


#pragma mark PROPERTIES
- (QELogModel *)model
{
    //    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[model retain] autorelease];
} // model

- (void)setModel:(QELogModel *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (newValue != model) {
        id temp = model;
        model = [newValue retain];
        [temp release];
    } // if
} // setModel:



#pragma mark OVERRIDDEN METHODS
- (NSString *)windowNibName
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    // Override returning the nib file name of the document
    // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
    return MAIN_WINDOW_NIB_NAME;
} // windowNibName


- (void)makeWindowControllers
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    // Overridden to create window controller--and window--using QELogWindowController
    // instead of NSWindowController
    QELogWindowController *wc = [[QELogWindowController alloc] initWithWindowNibName:[self windowNibName]];
    [self addWindowController:wc];
    [self setLogWindow:wc];
    [wc release];
} // makeWindowControllers


- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [super windowControllerDidLoadNib:aController];
    
    if ([[aController windowNibName] isEqual:MAIN_WINDOW_NIB_NAME]) {
        NSLog(@"  nib loaded for main document window");
        // Add any code here that needs to be executed once the windowController has loaded the document's window.
    } else if ([[aController windowNibName] isEqual:SECTIONS_WINDOW_NIB_NAME]) {
        NSLog(@"  nib loaded for sections window");
    } else {
        NSLog(@"  WARNING: unexpected nib file loaded for window controller");
    } // else
} // windowControllerDidLoadNib:

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    // Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil.
    
    // You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
    
    // For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[self model]];    
    if (!data && (outError != NULL) ) {
		*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteUnknownError userInfo:nil];
    } // if
    return data;
} // dataOfType:error:


- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    // Insert code here to read your document from the given data of the specified type.  If the given outError != NULL, ensure that you set *outError when returning NO.
    
    // You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead. 
    
    // For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead.
    BOOL readSuccess = NO;
    QELogModel *fileContents = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    if (nil != fileContents) {
        readSuccess = YES;
        [self setModel:fileContents];
    } else if ( outError != NULL ) {
		*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadUnknownError userInfo:nil];
    } // else if
    return readSuccess;
} // readFromData:ofType:error:


- (void)windowWillClose:(NSNotification *)notification
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSString *nibName = [[[notification object] windowController] windowNibName];
    if ([nibName isEqual:MAIN_WINDOW_NIB_NAME]) {
        // closing main document window
        NSLog(@"  closing main document window");
        [self setLogWindow:nil];
    } else if ([nibName isEqual:SECTIONS_WINDOW_NIB_NAME]) {
        NSLog(@"  closing sections window");
        [self setSecWindow:nil];
    } else {
        NSLog(@"  WARNING: closing unrecognized window");
    } // else
} // close
@end


@implementation QELogDocument (private)
#pragma mark PRIMITIVE OPERATIONS
- (void)restoreExchange:(NSString *)value
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[[self undoManager] prepareWithInvocationTarget:self] clearExchange];
    [[self logWindow] setEntrySrc:value];
    [[self undoManager] setActionName:@"Clear"];
} // restoreExchange:


- (void)uncreateQso:(QEContact *)qso fromExchange:(NSString *)src
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [[[self undoManager] prepareWithInvocationTarget:self] createQsoWithNewExchange:[[self logWindow] entrySrc]];
    [[self model] removeContact:qso];
    [[self logWindow] setEntrySrc:src];
    [[self undoManager] setActionName:@"Enter"];
    [self updateSentExchange];
} // uncreateQso:fromExchange:


#pragma mark PRIVATE PROPERTIES
- (QELogWindowController *)logWindow
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[logWindow retain] autorelease];
} // logWindow

- (void)setLogWindow:(QELogWindowController *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (logWindow != newValue) {
        id tmp = logWindow;
        logWindow = [newValue retain];
        [logWindow setDoc:self];
        [tmp release];
    } // if
} // setLogWindow:


- (QESectionsWindowController *)secWindow
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[secWindow retain] autorelease];
} // secWindow

- (void)setSecWindow:(QESectionsWindowController *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (secWindow != newValue) {
        id tmp = secWindow;
        secWindow = [newValue retain];
        [tmp release];
    } // if
} // setSecWindow:
@end
